﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;

namespace TrainBankCardChecker
{
    public class BankCardCheckMgr
    {
        private static bool _isEnable = false;
        /// <summary>
        /// 是否可用（在调用校验之前，应首先校验是否校验功能开通开用，如果不可用，则会造成空跑发生）
        /// </summary>
        public static bool IsEnable
        {
            get
            {
                // 处理：根据一定的规则判定是否进行了开启
                _isEnable = true;
                return _isEnable;
            }
        }

        #region 校验

        /// <summary>
        /// 校验银行卡信息（两要素校验）
        /// </summary>
        /// <param name="accountNo">银行卡号</param>
        /// <param name="accountName">户名、姓名</param>
        /// <returns></returns>
        public static BankCardCheckResult Check(string accountNo, string accountName)
        {
            var param = new BankCardCheckInfo(accountNo, accountName);
            var failMsg = param.Check();
            if (!string.IsNullOrEmpty(failMsg))
            {
                // 不抛出异常，不影响其它数据校验
                return new BankCardCheckResult
                {
                    Code = 1,
                    Message = failMsg
                };
            }

            // 系统内部校验
            CheckInInner(param);

            if (!_isEnable)
            {
                throw new Exception("当前校验服务未开通，请联系财务开通后再进行校验！");
            }
            // 调用接口校验
            var service = GetService();
            var result = service.Check(accountNo, accountName);
            try
            {
                SaveCheckSuccessInfo(param);
            }
            catch (Exception ex)
            {

            }
            return result;
        }

        /// <summary>
        /// 校验银行卡信息（三要素校验）
        /// </summary>
        /// <param name="accountNo">银行卡号</param>
        /// <param name="accountName">户名、姓名</param>
        /// <param name="idCardNo">证件号（证件号，证件类型为空时为身份证号）</param>
        /// <param name="idCardType">证件类型（可为空，证件号不为空时有效）</param>
        /// <returns></returns>
        public static BankCardCheckResult Check(string accountNo, string accountName, string idCardNo, string idCardType)
        {
            var param = new BankCardCheckInfo(accountNo, accountName, idCardNo, idCardType);
            var failMsg = param.Check();
            if (!string.IsNullOrEmpty(failMsg))
            {
                // 不抛出异常，不影响其它数据校验
                return new BankCardCheckResult
                {
                    Code = 1,
                    Message = failMsg
                };
            }

            // 系统内部校验
            CheckInInner(param);

            if (!_isEnable)
            {
                throw new Exception("当前校验服务未开通，请联系财务开通后再进行校验！");
            }
            // 调用接口校验
            var service = GetService();
            var result = service.Check(accountNo, accountName);
            return result;
        }

        /// <summary>
        /// 校验银行卡信息（四要素校验）
        /// </summary>
        /// <param name="accountNo">银行卡号</param>
        /// <param name="accountName">户名、姓名</param>
        /// <param name="idCardNo">证件号（证件号，证件类型为空时为身份证号）</param>
        /// <param name="idCardType">证件类型（可为空，证件号不为空时有效）</param>
        /// <param name="phone">电话号码</param>
        /// <returns></returns>
        public static BankCardCheckResult Check(string accountNo, string accountName, string idCardNo, string idCardType, string phone)
        {
            var param = new BankCardCheckInfo(accountNo, accountName, idCardNo, idCardType, phone);
            return Check(param, (service, checkedInfo) => service.Check(accountNo, accountName, idCardNo, idCardType, phone));
        }

        /// <summary>
        /// 校验
        /// </summary>
        /// <param name="checkedInfo">校验数据</param>
        /// <param name="check">校验方法</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        private static BankCardCheckResult Check(BankCardCheckInfo checkedInfo, Func<IBankCardChecker, BankCardCheckInfo, BankCardCheckResult> check)
        {
            var failMsg = checkedInfo.Check();
            if (!string.IsNullOrEmpty(failMsg))
            {
                // 不抛出异常，不影响其它数据校验
                return new BankCardCheckResult
                {
                    Code = 1,
                    Message = failMsg
                };
            }

            // 系统内部校验
            CheckInInner(checkedInfo);

            if (!_isEnable)
            {
                throw new Exception("当前校验服务未开通，请联系财务开通后再进行校验！");
            }
            // 调用接口校验
            var service = GetService();

            var result = check(service, checkedInfo);
            try
            {
                SaveCheckSuccessInfo(checkedInfo);
            }
            catch (Exception ex)
            {

            }
            return result;
        }

        /// <summary>
        /// 系统内部校验
        /// </summary>
        /// <param name="checkedInfo">校验参数</param>
        /// <returns></returns>
        private static BankCardCheckInnerResult CheckInInner(BankCardCheckInfo checkedInfo)
        {
            // 执行成功校验失败
            return null;
        }

        /// <summary>
        /// 保存校验成功数据（在校验成功后，可对正确数据进行记录）
        /// </summary>
        /// <param name="checkedInfo"></param>
        private static void SaveCheckSuccessInfo(BankCardCheckInfo checkedInfo)
        {
            // TODO：
        }
        #endregion

        #region Cache

        // 服务实例缓存
        private static Dictionary<string, IBankCardChecker> _serviceCache = new Dictionary<string, IBankCardChecker>();
        private static object _lock = new object();

        /// <summary>
        /// 获取接口服务实例
        /// </summary>
        /// <returns></returns>
        private static IBankCardChecker GetService()
        {
            var configClassFullName = GetConfig();
            if (_serviceCache.ContainsKey(configClassFullName))
            {
                return _serviceCache[configClassFullName];
            }
            lock (_lock)
            {
                if (_serviceCache.ContainsKey(configClassFullName))
                {
                    return _serviceCache[configClassFullName];
                }
                Register(configClassFullName);
            }
            return _serviceCache[configClassFullName];
        }

        /// <summary>
        /// 从配置中读取配置接口（获取当前业务单位单位所指定的接口）
        /// </summary>
        /// <returns></returns>
        private static string GetConfig()
        {
            // TODO：从配置中读取配置接口（可能配置有多个接口）
            return "";
        }

        /// <summary>
        /// 注册接口服务实例
        /// </summary>
        /// <param name="classFullName"></param>
        private static void Register(string classFullName)
        {
            // 使用反射注册服务实例
        }

        #endregion

        #region Assistance 

        #endregion
    }

    /// <summary>
    /// 校验参数
    /// </summary>
    [Serializable]
    public class BankCardCheckInfo
    {
        #region Properties 
        /// <summary>
        /// 校验要素<see cref="CheckElemEnum"/>
        /// </summary>
        public CheckElemEnum CheckElem { get; private set; }

        /// <summary>
        /// 银行卡号
        /// </summary>
        public string AccountNo { get; private set; }

        /// <summary>
        /// 户名
        /// </summary>
        public string AccountName { get; private set; }

        /// <summary>
        /// 证件号
        /// </summary>
        public string IDCardNo { get; private set; }

        /// <summary>
        /// 手机号
        /// </summary>
        public string PhoneNo { get; private set; }

        /// <summary>
        /// 证件类型
        /// </summary>
        public string IDCardType { get; private set; }

        /// <summary>
        /// 银行卡CVN2
        /// </summary>
        [Obsolete("本属性不在接口设计校验范围内")]
        public string CVN2 { get; set; }

        /// <summary>
        /// 银行卡有效期
        /// </summary>
        [Obsolete("本属性不在接口设计校验范围内")]
        public string Expired { get; set; }

        #endregion

        #region Ctor

        public BankCardCheckInfo(string accountNo, string accountName)
        {
            this.CheckElem = CheckElemEnum.T0201;
            this.AccountNo = accountNo;
            this.AccountName = accountName;
        }
        public BankCardCheckInfo(string accountNo, string accountName, string idCardNo, string idCardType)
        {
            this.CheckElem = CheckElemEnum.T0301;
            this.AccountNo = accountNo;
            this.AccountName = accountName;
            this.IDCardNo = idCardNo;
            this.IDCardType = idCardType;
        }

        public BankCardCheckInfo(string accountNo, string accountName, string idCardNo, string idCardType, string phoneNo)
        {
            this.CheckElem = CheckElemEnum.T0401;
            this.AccountNo = accountNo;
            this.AccountName = accountName;
            this.IDCardNo = idCardNo;
            this.IDCardType = idCardType;
            this.PhoneNo = phoneNo;
        }

        #endregion

        #region Business Methods

        /// <summary>
        /// 校验参数（根据要素类型）
        /// </summary>
        /// <returns>验证成功返回空，验证失败返回失败消息</returns>
        /// <exception cref="Exception"></exception>
        public string Check()
        {
            var result = string.Empty;
            if (string.IsNullOrWhiteSpace(this.AccountNo))
            {
                result+= "校验失败，银行卡号为空";
            }
            if (string.IsNullOrWhiteSpace(this.AccountName))
            {
                if (this.CheckElem == CheckElemEnum.T0201 || this.CheckElem == CheckElemEnum.T0301 || this.CheckElem == CheckElemEnum.T0401 || this.CheckElem == CheckElemEnum.T0601)
                {
                    result += "校验失败，户名为空";
                }
            }
            if (string.IsNullOrWhiteSpace(this.IDCardNo))
            {
                if (this.CheckElem == CheckElemEnum.T0202 || this.CheckElem == CheckElemEnum.T0301 || this.CheckElem == CheckElemEnum.T0401 || this.CheckElem == CheckElemEnum.T0601)
                {
                    result += "校验失败，证件号为空";
                }
            }
            if (string.IsNullOrWhiteSpace(this.PhoneNo))
            {
                if (this.CheckElem == CheckElemEnum.T0401 || this.CheckElem == CheckElemEnum.T0601)
                {
                    result += "校验失败，联系电话为空";
                }
            }
            if (this.CheckElem == CheckElemEnum.T0601)
            {
                if (string.IsNullOrWhiteSpace(this.CVN2))
                {
                    result += "校验失败，银行卡CVN2为空";
                }
                if (string.IsNullOrWhiteSpace(this.Expired))
                {
                    result += "校验失败，银行卡有效期为空";
                }
            }
            return result;
        } 
        #endregion
    }

    /// <summary>
    /// 校验要素枚举
    /// </summary>
    [Serializable]
    public enum CheckElemEnum
    {
        /// <summary>
        /// 两要素校验（卡号、户名）
        /// </summary>
        T0201,
        /// <summary>
        /// 两要素校验（卡号、身份证号）
        /// </summary>
        T0202,
        /// <summary>
        /// 三要素校验（卡号、姓名、身份证号）
        /// </summary>
        T0301,
        /// <summary>
        /// 四要素校验（卡号、姓名、身份证号、手机号）
        /// </summary>
        T0401,
        /// <summary>
        /// 六要素（卡号、姓名、身份证号码、手机号、CVN2、expired）
        /// </summary>
        T0601
    }

}
